home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Developer Essentials / DTS Sample Code / System 7.0 Samples / AEObject-Edition1.0.2 Sample / AEUtilities.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-09  |  23.5 KB  |  625 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. *
  3. *  Apple Developer Technical Support
  4. *
  5. *  AppleEvent utility routines
  6. *
  7. *  Program:AEObject-Edition Sample
  8. *  File:   AEUtilityRoutines.c - C Source
  9. *
  10. *  by: C.K. Haun <TR>
  11. *
  12. *  Copyright © 1991-1992 Apple Computer, Inc.
  13. *  All rights reserved.
  14. *
  15. *------------------------------------------------------------------------------
  16. * This file contains some generic and specific utility routines I wrote
  17. * to help with the AppleEvent manager.  The prime motivation for this file
  18. * is to NOT have to type in all the fields needed for many of the
  19. * AEM parameter accessing routines, since I do them so often.  
  20. * There aren't all that many calls here yet, this will grow as the AEM world grows
  21. *----------------------------------------------------------------------------*/
  22.  
  23.  
  24. #define __AEMU__
  25.  
  26. #include "Sampdefines.h"
  27.  
  28. #pragma segment AEUtils
  29. /* A little routine that returns a short from a descriptor */
  30. OSErr ShortFromDesc(short *theData, const AppleEvent *theDesc)
  31. {
  32.     OSErr myErr = noErr;
  33.     AEDesc tempDesc;
  34.     long temp;
  35.     if (theDesc->descriptorType == typeShortInteger) {
  36.         
  37.         temp = *((short *)*(theDesc->dataHandle));
  38.         *theData = temp;
  39.     } else {
  40.     /* if it wasn't a short to begin with, try and coerce it into a short */
  41.         myErr = AECoerceDesc(theDesc, typeShortInteger, &tempDesc);
  42.         if (!myErr) {
  43.             /* it coerced.  grab it */
  44.             temp = *((short *)*(tempDesc.dataHandle));
  45.             *theData = temp;
  46.             AEDisposeDesc(&tempDesc);
  47.         }
  48.     }
  49.     return(myErr);
  50.     
  51. }
  52. /* this has been replaced by my coercion handler, see AppleEventCore.c  */
  53. void PStringFromTextDesc(Str255 theString, const AEDesc *theDesc)
  54. {
  55.     theString[0] = GetHandleSize(theDesc->dataHandle);
  56.     BlockMove((Ptr)*theDesc->dataHandle, (Ptr)&theString[1], theString[0]);
  57.     
  58. }
  59.  
  60. /* Puts up the PPCBrowser, and creates a target address */
  61. /* based on the user selection */
  62. OSErr BrowseForTarget(AEDesc *theAddress)
  63. {
  64.     Str32 prompt1;
  65.     Str32 prompt2;
  66.     LocationNameRec theLoc;
  67.     PortInfoRec theRec;
  68.     OSErr myErr = noErr;
  69.     TargetID theID;
  70.     GetIndString(prompt1,kGeneralStrings,kPPCPrompt1);
  71.     GetIndString(prompt2,kGeneralStrings,kPPCPrompt2);
  72.     myErr = PPCBrowser(prompt1, prompt2, false, &theLoc, &theRec, nil, nil);
  73.     if (!myErr) {
  74.         /* make a target descriptor */
  75.         BlockMove(theRec.name.name, targetName, theRec.name.name[0] + 1);
  76.         ParamText(&targetName, "", "", "");
  77.         theID.name = theRec.name;
  78.         theID.location = theLoc;
  79.         myErr = AECreateDesc(typeTargetID, (Ptr)&theID, sizeof(theID), theAddress);
  80.         
  81.     }
  82.     mAEErrorDisplay("\pBrowser Error", myErr)
  83.     return(myErr);
  84. }
  85.  
  86. /* Makes an AppleEvent address descriptor based on the settings in the Dialog Box */
  87. /* in AppleEventCore.c */
  88. OSErr MakeAddress(AEDesc *theAddress)
  89. {
  90.     OSErr myErr = noErr;
  91.     ProcessSerialNumber myNumber;
  92.     switch (gAddressMode) {
  93.     /* Remember, if you use this case (using the PSN of kCurrentProcess) the  */
  94.     /* AppleEvent Manager will bypass the event loop and directly call (like a normal */
  95.     /* subroutine call) your handler, the event will _not_ come through */
  96.     /* WaitNextEvent */
  97.         case kSelfCur:
  98.             myNumber.highLongOfPSN = 0;
  99.             myNumber.lowLongOfPSN = kCurrentProcess;
  100.             myErr = AECreateDesc(typeProcessSerialNumber, (Ptr)&myNumber, sizeof(ProcessSerialNumber), theAddress);
  101.             break;
  102.     /* If you use your real PSN, then the event will come through WNE */        
  103.         case kSelfPSN:
  104.             myErr = AECreateDesc(typeProcessSerialNumber, (Ptr)&gOurSN, sizeof(ProcessSerialNumber), theAddress);
  105.             break;
  106.         case kOtherApp:
  107.             if (gTargetAddress.dataHandle == nil) {
  108.                 myErr = BrowseForTarget(theAddress);
  109.             } else {
  110.             /* If I already have one, duplicate it and pass it back */
  111.                 myErr = AEDuplicateDesc(&gTargetAddress, theAddress);
  112.             }
  113.             break;
  114.     }
  115.     mAEErrorDisplay("\pMakeAddress ", myErr)
  116.     return(myErr);
  117. }
  118.  
  119. /* generic sender, so I don't have to duplicate the various conditional code */
  120. /* (for replies, interactions, or whatever) all over */
  121. OSErr DoSend(AppleEvent *theEvent, AEDesc *reply)
  122. {
  123.     AEDesc *replyPointer = nil;
  124.     short response = 2;
  125.     OSErr myErr;
  126.     long timeOut = kAEDefaultTimeout;
  127.     if (gReplyMode)
  128.         replyPointer = reply;
  129.     if (gReplyMode == 1 && gAddressMode == 1) {
  130.         timeOut = 0;
  131.         response = CautionAlert(kBadMix, (ModalFilterProcPtr)standardAlertFilter);
  132.     }
  133.     if (response == 2) {
  134.         myErr = AESend(theEvent, replyPointer,
  135.                        (gSendInteractArray[gAESendInteraction] + gAESwitchLayer) + gReplyLevels[gReplyMode], kAENormalPriority,
  136.                        timeOut, (IdleProcPtr)CommonIdleFunction, nil);
  137.         
  138.         mAEErrorDisplay("\pAESend in DoSend ", myErr)
  139.     } else {
  140.         myErr = userCanceledErr;
  141.     }
  142.     return(myErr);
  143. }
  144.  
  145. /* lil routine that will print out actual error text for AEM errors, since I */
  146. /* got real tired of trying to remeber what -1723 was. */
  147. /* revised to reflect the new error codes, and to use my ERST <ckh 1.0.2>*/
  148. /* resource <ckh 1.0.2>*/
  149. void AEErrorText(OSErr theError)
  150. {
  151.     Str63 theWords;
  152.     Ptr theErrors;
  153.     OSErr tempError;
  154.     register qq;
  155.     short errCount;
  156.     Byte stringLen;
  157.     /* get my errors <ckh 1.0.2>*/
  158.     Handle scratch = GetResource(kErrorStringResourceType,kTheErrorStrings);
  159.     theWords[0] = 0;
  160.     if(scratch){
  161.         /* if I got it, lock it and deref <ckh 1.0.2>*/
  162.         HLock(scratch);
  163.         theErrors = *scratch;
  164.         errCount =  *((short *)theErrors);
  165.         /* position to the first error code <ckh 1.0.2>*/
  166.         theErrors = theErrors+sizeof(short);
  167.         errCount--;
  168.         for(qq = 0;qq<errCount;qq++){
  169.             tempError =  *((short *)theErrors);
  170.             theErrors = theErrors + sizeof (OSErr);
  171.             /* get the string count, we'll need this whatever we do <ckh 1.0.2>*/
  172.             stringLen = *theErrors;
  173.             stringLen ++;    
  174.             if(tempError == theError){
  175.                 /* it's this one, theErrors points to the string <ckh 1.0.2>*/
  176.                 BlockMove(theErrors,(Ptr)&theWords,stringLen);
  177.                 break;
  178.                 
  179.                 } else {
  180.                 /* next errror please <ckh 1.0.2>*/
  181.                 theErrors = theErrors + stringLen;
  182.                 }
  183.             }
  184.         if(theWords[0] == 0){
  185.             GetIndString(theWords,kGeneralStrings,kUnknownError);
  186.             }    
  187.         AddAEText(theWords);
  188.         HUnlock(scratch);
  189.         ReleaseResource(scratch);
  190.         }
  191. }
  192.  
  193. /* this just pumps out the returned data to the AEWindow */
  194. /* just a utility for this sample */
  195. void DisplayReturnedData(AEDesc *reply)
  196. {
  197.     AEDesc theData;
  198.     OSErr myErr;
  199.     long errorCode = 0;
  200.     DescType returnedType;
  201.     Size returnedSize;
  202.     Str255 returnedText;
  203.     /* I can do most of this by asking for typeChar and getting the desc. */
  204.     /* this is because the AEM can coerce any numeric data to typeChar */
  205.     /* (as described in the AEM chapter of IM VI) */
  206.     /* For things that the AEM _doesn't_ know about, I will install */
  207.     /* coercion handlers! */
  208.     /* if the coercion completely fails, because I got something I no nothing about, I bail */
  209.     mVerboseOutput("\p\n Returned Data was : ")
  210.     myErr = AEGetParamDesc(reply, keyDirectObject, typeChar, &theData);
  211.     if (!myErr) {
  212.         long size = GetHandleSize(theData.dataHandle);
  213.         HLock(theData.dataHandle);
  214.         
  215.         AddToAEWindow((Ptr)*(theData.dataHandle), size);
  216.         
  217.     } else {
  218.         /* get it as a wildcard, and just show me the descType */
  219.         myErr = AEGetParamDesc(reply, keyDirectObject, typeWildCard, &theData);
  220.         AddToAEWindow((Ptr)&theData.descriptorType, kFour);
  221.     }
  222.     /* I got a desc, I need to dispose a desc */
  223.     if (!myErr)
  224.         AEDisposeDesc(&theData);
  225.     else
  226.         AddAEText("\p not available");
  227.     /* see if there was an 'errs' or 'errn' added */
  228.     myErr = AEGetParamPtr(reply, keyErrorNumber, typeLongInteger, &returnedType, (Ptr)&errorCode, sizeof(long), &returnedSize);
  229.     if (myErr && myErr != errAEDescNotFound) {
  230.         
  231.         mVerboseOutput("\p\n Had an error descriptor, but I can't access it")
  232.     }
  233.     if (!myErr) {
  234.         mVerboseOutput("\p\n Error number (errn) returned, was: ")
  235.         AddAENum(errorCode);
  236.         AEErrorText(errorCode);
  237.     }
  238.     /* try for the error string */
  239.     myErr = AEGetParamPtr(reply, keyErrorString, typeMyPString, &returnedType, (Ptr)&returnedText, 255, &returnedSize);
  240.     if (!myErr) {
  241.         mVerboseOutput("\p\n Error string (errs) returned, was: ")
  242.         AddAEText(&returnedText);
  243.     }
  244. }
  245.  
  246.  
  247. /* DoObjectDefinition drives the dialog that sets up the default containers */
  248. /* for this sample, boring dialog stuff */
  249. void DoObjectDefinition(short which)
  250. {
  251.     DialogPtr tdial;
  252.     short hitItem = 0;
  253.     Boolean r5, r6;
  254.     Str32 tempNum;
  255.     register qq;
  256.     long realNum;
  257.     DescType shapeTypes[] =  {
  258.        cGraphicLine, cRectangle, cOval
  259.     };
  260.     tdial = SetUpObjectDialog(which);
  261.     ShowWindow(tdial);
  262.     while (hitItem != ok && hitItem != cancel) {
  263.         ModalDialog((ModalFilterProcPtr)standardDialogFilter, &hitItem);
  264.         switch (which) {
  265.             case kSetWindowObject:
  266.                 switch (hitItem) {
  267.                     case kWByIndex:
  268.                     case kWByName:
  269.                         if (hitItem == kWByIndex) {
  270.                             r5 = true;
  271.                             r6 = false;
  272.                         } else {
  273.                             r5 = false;
  274.                             r6 = true;
  275.                         }
  276.                         SetCtlValue(SnatchHandle(tdial, kWByIndex), r5);
  277.                         SetCtlValue(SnatchHandle(tdial, kWByName), r6);
  278.                         
  279.                         break;
  280.                 }
  281.                 break;
  282.             case kSetTextObject:
  283.                 switch (hitItem) {
  284.                     case kWordIndex:                        /* checkbox only to worry about */
  285.                         SetCtlValue(SnatchHandle(tdial, kWordIndex), (GetCtlValue(SnatchHandle(tdial, kWordIndex)) ? 0 : 1));
  286.                 }
  287.                 break;
  288.             case kSetShapeObject:
  289.                 switch (hitItem) {
  290.                     case kLineRadio:
  291.                     case kRectangleRadio:
  292.                     case kOvalRadio:
  293.                         /* find out which one is true */
  294.                         for (qq = kLineRadio; qq < kOvalRadio + 1; qq++) {
  295.                             if (GetCtlValue(SnatchHandle(tdial, qq))) {
  296.                                 if (!(qq == hitItem)) {
  297.                                     SetCtlValue(SnatchHandle(tdial, qq), false);
  298.                                     SetCtlValue(SnatchHandle(tdial, hitItem), true);
  299.                                 }
  300.                             }
  301.                         }
  302.                         break;
  303.                 }
  304.                 break;
  305.         }
  306.     }
  307.     /* make the changes permenent */
  308.     if (hitItem == ok) {
  309.         gPreferences.prefsChanged = true;
  310.         switch (which) {
  311.             case kSetWindowObject:
  312.                 HLock((Handle)gWindObjSpecHandle);
  313.                 if (GetCtlValue(SnatchHandle(tdial, kWByIndex))) {
  314.                     /* going by absolute position */
  315.                     (*gWindObjSpecHandle)->form = formAbsolutePosition;
  316.                     GetIText((Handle)SnatchHandle(tdial, kWIndexNum), tempNum);
  317.                     StringToNum(tempNum, &realNum);
  318.                     (*gWindObjSpecHandle)->u.index = realNum;
  319.                 } else {
  320.                     /* going by name */
  321.                     (*gWindObjSpecHandle)->form = formName;
  322.                     /* put the name where it belongs */
  323.                     GetIText((Handle)SnatchHandle(tdial, kWIndexName), (*gWindObjSpecHandle)->u.name);
  324.                     
  325.                 }
  326.                 HUnlock((Handle)gWindObjSpecHandle);
  327.                 break;
  328.             case kSetTextObject:
  329.                 
  330.                 HLock((Handle)gTextObjSpecHandle);
  331.                 /* fewer choices here */
  332.                 GetIText((Handle)SnatchHandle(tdial, kTextONumber), tempNum);
  333.                 
  334.                 StringToNum(tempNum, &realNum);
  335.                 (*gTextObjSpecHandle)->u.index = realNum;
  336.                 (*gTextObjSpecHandle)->andWord = GetCtlValue(SnatchHandle(tdial, kWordIndex));
  337.                 /* see if word is being asked for */
  338.                 if ((*gTextObjSpecHandle)->andWord) {
  339.                     GetIText((Handle)SnatchHandle(tdial, kWordIndexString), tempNum);
  340.                     StringToNum(tempNum, &realNum);
  341.                     (*gTextObjSpecHandle)->wordNumber = realNum;
  342.                     
  343.                 }
  344.                 HUnlock((Handle)gTextObjSpecHandle);
  345.                 break;
  346.             case kSetShapeObject:
  347.                 HLock((Handle)gShapeObjSpecHandle);
  348.                 for (qq = kLineRadio; qq < kOvalRadio + 1; qq++) {
  349.                     if (GetCtlValue(SnatchHandle(tdial, qq))) {
  350.                         (*gShapeObjSpecHandle)->type = qq - kLineRadio;
  351.                         (*gShapeObjSpecHandle)->form = shapeTypes[qq - kLineRadio];
  352.                         break;
  353.                     }
  354.                 }
  355.                 /* and the index number */
  356.                 GetIText((Handle)SnatchHandle(tdial, kSIEditLine), tempNum);
  357.                 StringToNum(tempNum, &realNum);
  358.                 (*gShapeObjSpecHandle)->u.index = realNum;
  359.                 HUnlock((Handle)gShapeObjSpecHandle);
  360.                 break;
  361.         }
  362.     }
  363.     DisposDialog(tdial);
  364. }
  365.  
  366. /* Anther case of not wanting to type dialog code all over the sample */
  367. DialogPtr SetUpObjectDialog(short which)
  368. {
  369.     DialogPtr tdial = CommonDStart(which, nil, nil);
  370.     short tempItem;
  371.     Str63 tempString;
  372.     switch (which) {
  373.         
  374.         case kSetWindowObject:
  375.             HLock((Handle)gWindObjSpecHandle);
  376.             if ((*gWindObjSpecHandle)->form == 0) {
  377.                 tempItem = kWPosRadio;                               /* default for the first time the app is run */
  378.             } else {
  379.                 
  380.                 if ((*gWindObjSpecHandle)->form == formAbsolutePosition) {
  381.                     
  382.                     tempItem = kWPosRadio;
  383.                     NumToString((*gWindObjSpecHandle)->u.index, tempString);
  384.                     SetIText((Handle)SnatchHandle(tdial, kWPosNum), tempString);
  385.                 } else {
  386.                     tempItem = kWTitleRadioSet;
  387.                     SetIText((Handle)SnatchHandle(tdial, kWTitleELine), (*gWindObjSpecHandle)->u.name);
  388.                 }
  389.             }
  390.             SetCtlValue(SnatchHandle(tdial, tempItem), true);
  391.             HUnlock((Handle)gWindObjSpecHandle);
  392.             break;
  393.         case kSetTextObject:
  394.             HLock((Handle)gTextObjSpecHandle);
  395.             /* fewer choices here */
  396.             NumToString((*gTextObjSpecHandle)->u.index, tempString);
  397.             SetIText((Handle)SnatchHandle(tdial, kWPosRadio), tempString);
  398.             /* see if word is being asked for */
  399.             if ((*gTextObjSpecHandle)->andWord) {
  400.                 SetCtlValue(SnatchHandle(tdial, kWTitleRadioSet), true);
  401.                 NumToString((*gTextObjSpecHandle)->wordNumber, tempString);
  402.                 SetIText((Handle)SnatchHandle(tdial, kWPosNum), tempString);
  403.                 
  404.             }
  405.             HUnlock((Handle)gTextObjSpecHandle);
  406.             break;
  407.         case kSetShapeObject:
  408.             HLock((Handle)gShapeObjSpecHandle);
  409.             if (!(*gShapeObjSpecHandle)->u.index)
  410.                 (*gShapeObjSpecHandle)->u.index = 1;
  411.             NumToString((*gShapeObjSpecHandle)->u.index, tempString);
  412.             SetIText((Handle)SnatchHandle(tdial, kSIEditLine), tempString);
  413.             SetCtlValue(SnatchHandle(tdial, ((*gShapeObjSpecHandle)->type) + kLineRadio), true);
  414.             /* byIndex defaults to on for now */
  415.             SetCtlValue(SnatchHandle(tdial, kSByIndexRadio), true);
  416.             
  417.             break;
  418.         default:
  419.             break;
  420.     }
  421.     return(tdial);
  422. }
  423.  
  424.  
  425.  
  426.  
  427.  
  428. /* this is a central point to add keyErrorText and keyErrorNumber  */
  429. /* parameters to a reply */
  430. /* just a handy thing to do. */
  431. /* It first checks to see if an error is already recorded, if there is one */
  432. /* (for an earlier stage in the process) they we exit, since the user will have to */
  433. /* deal with the ealier problem before they tackle the one we've just been called  */
  434. /* to add */
  435. /* •••• BE SURE that you null out the gCurrentReply (or whatever you use) pointer */
  436. /* when you exit from your handler, or you could end up writing to a desc that isn't  */
  437. /* there.  And of course, if you send events to yourself from within a handler */
  438. /* you're going to have to use a differrent method than this.  It's a sample, see? */
  439. void AddToReply(ConstStr255Param theWords, long theError)
  440. {
  441.     OSErr myErr = noErr;
  442.     long errNo;
  443.     DescType returnedType;
  444.     Size returnedSize;
  445.     
  446.     /* First, is therre a reply hanging out? */
  447.     if (gCurrentReply) {
  448.         /* test to see if there is one already*/
  449.         myErr = AEGetParamPtr(gCurrentReply, keyErrorNumber, typeLongInteger, &returnedType, (Ptr)&errNo, sizeof(long),
  450.                               &returnedSize);
  451.         
  452.         if (myErr == errAEDescNotFound) {
  453.             /* cool, press on.  */
  454.             myErr = AEPutParamPtr(gCurrentReply, keyErrorNumber, typeLongInteger, (Ptr)&theError, sizeof(long));
  455.             if (!myErr)
  456.                 myErr = AEPutParamPtr(gCurrentReply, keyErrorString, typeChar, (Ptr)&theWords[1], theWords[0]);
  457.             
  458.         }
  459.     }
  460. }
  461.  
  462. OSErr MakeTypeRect(CShapeObjHandle theShape, AEDesc *theValue)
  463. {
  464.     OSErr myErr = noErr;
  465.     AEDesc pixDesc;
  466.     AEDescList theList;
  467.     RGBColor black =  {
  468.         0, 0, 0
  469.     };
  470.     RGBColor white =  {
  471.         0xffff, 0xffff, 0xffff
  472.     };
  473.     short penSize = 1;
  474.     long copyWord = kAEQDCopy;
  475.     ShapesHandle theRealShape = (*theShape)->theShape;
  476.     HLock((Handle)theRealShape);
  477.     /* Now, a typeRectangle is a bunch of stuff, and as the AE Registry so clearly says... */
  478.     /* "Note that the Apple Event Manager can coerce any Apple event record into any 
  479.     other descriptor type. A special coercion handler is not required."
  480.     */
  481.     /* If you always wondered what that meant (I know I did) then watch */
  482.     /* create a list that is a record */
  483.     myErr = AECreateList(nil, nil, true, &theList);
  484.     /* now start adding all the junk I have lying around, rectangle, color, kitchen sink.... */
  485.     if (!myErr)
  486.         myErr = MakeSinglePixelMap(&pixDesc, &(*theRealShape)->theColor);
  487.     /* jeeez don't try and write code while the Finder is doing a copy across LocalTalk in the background Like I'm trying to now.... */
  488.     if (!myErr)
  489.         myErr = AEPutKeyDesc(&theList, keyAEPenPattern, &pixDesc);
  490.     if (!myErr)
  491.         myErr = AEPutKeyDesc(&theList, keyAEFillPattern, &pixDesc);
  492.     AEDisposeDesc(&pixDesc);
  493.     if (!myErr)
  494.         myErr = MakeSinglePixelMap(&pixDesc, &white);
  495.     if (!myErr)
  496.         myErr = AEPutKeyDesc(&theList, keyAEFillColor, &pixDesc);
  497.     AEDisposeDesc(&pixDesc);
  498.     if (!myErr)
  499.         myErr = AEPutKeyPtr(&theList, keyAEPenWidth, typeShortInteger, (Ptr)&penSize, sizeof(short));
  500.     if (!myErr)
  501.         myErr = AEPutKeyPtr(&theList, keyAETransferMode, typeEnumeration, (Ptr)©Word, sizeof(long));
  502.     
  503.     if (!myErr)
  504.         myErr = AEPutKeyPtr(&theList, keyAEBounds, typeQDRectangle, (Ptr)&(*theRealShape)->theRect, sizeof(Rect));
  505.     if (!myErr)
  506.         myErr = AEPutKeyPtr(&theList, keyAEDefinitionRect, typeQDRectangle, (Ptr)&(*theRealShape)->theRect, sizeof(Rect));
  507.     HUnlock((Handle)theRealShape);
  508.     /* and coerce it into what we want */
  509.     if (!myErr)
  510.         myErr = AECoerceDesc(&theList, typeRectangle, theValue);
  511.     AEDisposeDesc(&theList);
  512.     mAEErrorDisplay("\p\n Error creating typeRectangle", myErr)
  513.     return(myErr);
  514. }
  515.  
  516. /* MakeGraphicLine is similar to making a typeRectangle */
  517.  
  518. OSErr MakeGraphicLine(CShapeObjHandle theShape, AEDesc *theValue)
  519. {
  520.     OSErr myErr = noErr;
  521.     AEDesc emptyList;
  522.     AEDesc pixDesc;
  523.     AEDescList theList;
  524.     RGBColor black =  {
  525.         0, 0, 0
  526.     };
  527.     RGBColor white =  {
  528.         0xffff, 0xffff, 0xffff
  529.     };
  530.     short penSize = 1;
  531.     long copyWord = kAEQDCopy;
  532.     DescType noArr = kAENoArrow;
  533.     ShapesHandle theRealShape = (*theShape)->theShape;
  534.     HLock((Handle)theRealShape);
  535.     myErr = AECreateList(nil, nil, true, &theList);
  536.     /* now start adding all the junk I have lying around, rectangle, color, kitchen sink.... */
  537.     if (!myErr)
  538.         myErr = MakeSinglePixelMap(&pixDesc, &(*theRealShape)->theColor);
  539.     /* jeeez don't try and write code while the Finder is doing a copy across LocalTalk in the background Like I'm trying to now.... */
  540.     if (!myErr)
  541.         myErr = AEPutKeyDesc(&theList, keyAEPenPattern, &pixDesc);
  542.     if (!myErr)
  543.         myErr = AEPutKeyDesc(&theList, keyAEPenColor, &pixDesc);
  544.     AEDisposeDesc(&pixDesc);
  545.     if (!myErr)
  546.         myErr = AEPutKeyPtr(&theList, keyAEPenWidth, typeShortInteger, (Ptr)&penSize, sizeof(short));
  547.     if (!myErr)
  548.         myErr = AEPutKeyPtr(&theList, keyAETransferMode, typeEnumeration, (Ptr)©Word, sizeof(long));
  549.     
  550.     if (!myErr)
  551.         myErr = AEPutKeyPtr(&theList, keyAEBounds, typeQDRectangle, (Ptr)&(*theRealShape)->theRect, sizeof(Rect));
  552.     if (!myErr)
  553.         myErr = AEPutKeyPtr(&theList, keyAELineArrow, typeEnumeration, (Ptr)&noArr, sizeof(DescType));
  554.     /* we have no dash styles, so add an empty list */
  555.     myErr = AECreateList(nil, nil, false, &emptyList);
  556.     if (!myErr)
  557.         myErr = AEPutKeyDesc(&theList, keyAEDashStyle, &emptyList);
  558.     AEDisposeDesc(&emptyList);
  559.     if (!myErr)
  560.         myErr = AEPutKeyPtr(&theList, keyAEStartPoint, typeQDRectangle, (Ptr)&(*theRealShape)->theRect, sizeof(Point));
  561.     if (!myErr)
  562.         myErr = AEPutKeyPtr(&theList, keyAEStartPoint, typeQDRectangle, (Ptr)&(*theRealShape)->theRect.bottom, sizeof(Point));
  563.     
  564.     HUnlock((Handle)theRealShape);
  565.     /* and coerce it into what we want */
  566.     if (!myErr)
  567.         myErr = AECoerceDesc(&theList, typeGraphicLine, theValue);
  568.     AEDisposeDesc(&theList);
  569.     mAEErrorDisplay("\p\n Error creating typeGraphicLine", myErr)
  570.     return(myErr);
  571. }
  572.  
  573. /* Now some of the definitions in the AE Registry are rather broad, but they */
  574. /* really need to be.  SO you'll want little routines like this */
  575. OSErr MakeSinglePixelMap(AEDesc *thePlace, RGBColor *theColor)
  576. {
  577.     OSErr myErr = noErr;
  578.     AEDescList thePixelList, tempList;
  579.     AEDesc scratchDesc;
  580.     long copyWord = kAEQDCopy;
  581.     Rect miniRect =  {
  582.         0, 0, 1, 1
  583.     };
  584.     myErr = AECreateList(nil, nil, false, &thePixelList);
  585.     if (!myErr)
  586.         myErr = AECreateDesc(typeRGBColor, (Ptr)theColor, sizeof(RGBColor), &scratchDesc);
  587.     if (!myErr)
  588.         myErr = AEPutDesc(&thePixelList, 0, &scratchDesc);
  589.     if (!myErr)
  590.         myErr = AEDisposeDesc(&scratchDesc);
  591.     /* now create the other list */
  592.     if (!myErr)
  593.         myErr = AECreateList(nil, nil, true, &tempList);
  594.     /* add the pixels */
  595.     if (!myErr)
  596.         myErr = AEPutKeyDesc(&tempList, typePixMapMinus, &thePixelList);
  597.     if (!myErr)
  598.         myErr = AEDisposeDesc(&thePixelList);
  599.     if (!myErr)
  600.         myErr = AECreateDesc(typeQDRectangle, (Ptr)&miniRect, sizeof(Rect), &scratchDesc);
  601.     /* add it */
  602.     if (!myErr)
  603.         myErr = AEPutKeyDesc(&tempList, keyAEBounds, &scratchDesc);
  604.     if (!myErr)
  605.         myErr = AEDisposeDesc(&scratchDesc);
  606.     /* and the transfer mode, I'm using Copy for all of these */
  607.     if (!myErr)
  608.         myErr = AECreateDesc(typeEnumeration, (Ptr)©Word, sizeof(long), &scratchDesc);
  609.     /* add it */
  610.     if (!myErr)
  611.         myErr = AEPutKeyDesc(&tempList, keyAETransferMode, &scratchDesc);
  612.     if (!myErr)
  613.         myErr = AEDisposeDesc(&scratchDesc);
  614.     /* and coerce thePlace into a typePixelMap */
  615.     if (!myErr)
  616.         myErr = AECoerceDesc(&tempList, typePixelMap, thePlace);
  617.     
  618.     /* See?  Simplicity itself */
  619.     mAEErrorDisplay("\p\n Error creating pixMap", myErr)
  620.     return(myErr);
  621. }
  622.  
  623.  
  624. #undef __AEMU__
  625.